package com.edfapp.costom;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @author hong
 * @description 描述
 * @time 2025/9/17 16:15
 **/
public class EDFParser {
    // EDF文件头信息
    private EDFHeader header;
    // 信号数据
    private List<double[]> signalData;

    public void parse(File edfFile) throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(edfFile, "r")) {
            // 读取文件头
            header = readHeader(raf);

            // 读取信号数据
            signalData = readSignalData(raf);
        }
    }

    // 读取EDF文件头
    private EDFHeader readHeader(RandomAccessFile raf) throws IOException {
        EDFHeader header = new EDFHeader();

        // 读取版本信息 (8字节)
        header.version = readFixedString(raf, 8).trim();

        // 读取用户标识 (80字节)
        header.patientId = readFixedString(raf, 80).trim();

        // 读取记录标识 (80字节)
        header.recordId = readFixedString(raf, 80).trim();

        // 读取开始日期 (8字节)
        header.startDate = readFixedString(raf, 8).trim();

        // 读取开始时间 (8字节)
        header.startTime = readFixedString(raf, 8).trim();

        // 读取头信息长度 (8字节)
        header.headerSize = Integer.parseInt(readFixedString(raf, 8).trim());

        // 读取EDF标识 (44字节)
        header.edfId = readFixedString(raf, 44).trim();

        // 读取数据记录数量 (8字节)
        header.numberOfRecords = Integer.parseInt(readFixedString(raf, 8).trim());

        // 读取每条记录的持续时间(秒) (8字节)
        header.recordDuration = Float.parseFloat(readFixedString(raf, 8).trim());

        // 读取信号数量 (4字节)
        header.numberOfSignals = Integer.parseInt(readFixedString(raf, 4).trim());

        // 读取每个信号的信息
        header.signalLabels = new String[header.numberOfSignals];
        header.transducerTypes = new String[header.numberOfSignals];
        header.physicalDimensions = new String[header.numberOfSignals];
        header.physicalMin = new float[header.numberOfSignals];
        header.physicalMax = new float[header.numberOfSignals];
        header.digitalMin = new int[header.numberOfSignals];
        header.digitalMax = new int[header.numberOfSignals];
        header.prefiltering = new String[header.numberOfSignals];
        header.samplesPerRecord = new int[header.numberOfSignals];

        // 信号标签 (每个16字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.signalLabels[i] = readFixedString(raf, 16).trim();
        }

        // 传感器类型 (每个80字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.transducerTypes[i] = readFixedString(raf, 80).trim();
        }

        // 物理维度 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.physicalDimensions[i] = readFixedString(raf, 8).trim();
        }

        // 物理最小值 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.physicalMin[i] = Float.parseFloat(readFixedString(raf, 8).trim());
        }

        // 物理最大值 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.physicalMax[i] = Float.parseFloat(readFixedString(raf, 8).trim());
        }

        // 数字最小值 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.digitalMin[i] = Integer.parseInt(readFixedString(raf, 8).trim());
        }

        // 数字最大值 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.digitalMax[i] = Integer.parseInt(readFixedString(raf, 8).trim());
        }

        // 预滤波 (每个80字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.prefiltering[i] = readFixedString(raf, 80).trim();
        }

        // 每条记录的样本数 (每个8字节)
        for (int i = 0; i < header.numberOfSignals; i++) {
            header.samplesPerRecord[i] = Integer.parseInt(readFixedString(raf, 8).trim());
        }

        // 保留字段 (每个32字节，通常不用处理)
        raf.skipBytes(32 * header.numberOfSignals);

        return header;
    }

    // 读取信号数据
    private List<double[]> readSignalData(RandomAccessFile raf) throws IOException {
        List<double[]> data = new ArrayList<>();

        // 移动到数据部分
        raf.seek(header.headerSize);

        // 对于每个信号初始化数组
        for (int i = 0; i < header.numberOfSignals; i++) {
            data.add(new double[header.numberOfRecords * header.samplesPerRecord[i]]);
        }

        // 读取每条记录
        for (int r = 0; r < header.numberOfRecords; r++) {
            // 读取每个信号的数据
            for (int s = 0; s < header.numberOfSignals; s++) {
                int samples = header.samplesPerRecord[s];
                double[] signal = data.get(s);
                int startIndex = r * samples;

                // 计算物理值转换因子
                float physRange = header.physicalMax[s] - header.physicalMin[s];
                int digitalRange = header.digitalMax[s] - header.digitalMin[s];
                float factor = physRange / digitalRange;

                // 读取样本并转换为物理值
                for (int i = 0; i < samples; i++) {
                    // EDF使用16位有符号整数存储数据
                    short digitalValue = raf.readShort();

                    // 转换为物理值
                    double physicalValue = header.physicalMin[s] +
                            (digitalValue - header.digitalMin[s]) * factor;

                    signal[startIndex + i] = physicalValue;
                }
            }
        }

        return data;
    }

    // 读取固定长度的字符串
    private String readFixedString(RandomAccessFile raf, int length) throws IOException {
        byte[] buffer = new byte[length];
        raf.readFully(buffer);
        String trim = new String(buffer, StandardCharsets.ISO_8859_1).trim();
        return trim;
    }
    // 获取所有通道名称/标签列表
    public List<String> getChannelLabels() {
        List<String> labels = new ArrayList<>();
        if (header != null && header.signalLabels != null) {
            for (String label : header.signalLabels) {
                labels.add(label);
            }
        }
        return labels;
    }
    // 根据通道名称获取对应的信号数据
    public double[] getSignalByChannelName(String channelName) {
        if (header == null || header.signalLabels == null || signalData == null) {
            return null;
        }

        for (int i = 0; i < header.signalLabels.length; i++) {
            if (header.signalLabels[i].equals(channelName)) {
                return signalData.get(i);
            }
        }
        return null;
    }

    // 根据索引获取通道名称
    public String getChannelLabel(int index) {
        if (header != null && header.signalLabels != null &&
                index >= 0 && index < header.signalLabels.length) {
            return header.signalLabels[index];
        }
        return null;
    }

    // 获取文件头信息
    public EDFHeader getHeader() {
        return header;
    }

    // 将所有通道数据导出到文本文件
    public void exportToTextFile(String outputFilePath) throws IOException {
        exportToTextFile(outputFilePath, false);
    }

    // 将所有通道数据导出到文本文件，可选择是否导出完整数据
    public void exportToTextFile(String outputFilePath, boolean exportAllData) throws IOException {
        if (header == null || signalData == null || header.signalLabels == null) {
            throw new IllegalStateException("请先解析EDF文件");
        }

        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(outputFilePath), StandardCharsets.UTF_8))) {

            // 写入头信息
            writer.write("=== EDF文件头信息 ===\n");
            writer.write("版本: " + header.version + "\n");
            writer.write("用户信息: " + header.patientId + "\n");
            writer.write("记录信息: " + header.recordId + "\n");
            writer.write("开始日期: " + header.startDate + "\n");
            writer.write("开始时间: " + header.startTime + "\n");
            writer.write("信号数量: " + header.numberOfSignals + "\n");
            writer.write("记录数量: " + header.numberOfRecords + "\n");
            writer.write("每条记录持续时间: " + header.recordDuration + "秒\n\n");

            // 写入通道信息
            writer.write("=== 通道信息 ===\n");
            for (int i = 0; i < header.numberOfSignals; i++) {
                writer.write("通道 " + i + ":\n");
                writer.write("  名称: " + header.signalLabels[i] + "\n");
                writer.write("  传感器类型: " + header.transducerTypes[i] + "\n");
                writer.write("  物理维度: " + header.physicalDimensions[i] + "\n");
                writer.write("  物理范围: " + header.physicalMin[i] + " - " + header.physicalMax[i] + "\n");
                writer.write("  数字范围: " + header.digitalMin[i] + " - " + header.digitalMax[i] + "\n");
                writer.write("  预滤波: " + header.prefiltering[i] + "\n");
                writer.write("  每条记录样本数: " + header.samplesPerRecord[i] + "\n");
                writer.write("  总样本数: " + (header.numberOfRecords * header.samplesPerRecord[i]) + "\n\n");
            }

            // 写入通道数据
            writer.write("=== 通道数据 ===\n");
            List<String> channels = getChannelLabels();

            for (int i = 0; i < channels.size(); i++) {
                String channelName = channels.get(i);
                double[] signalData = this.signalData.get(i);

                writer.write("===== " + channelName + " 数据 =====");
                writer.newLine();

                // 确定要导出的数据量
                int exportCount = exportAllData ? signalData.length : Math.min(1000, signalData.length);
                if (signalData.length > 1000 && !exportAllData) {
                    writer.write("(仅显示前1000个数据点，共" + signalData.length + "个)");
                    writer.newLine();
                }

                // 写入数据点，每行10个数据点，便于阅读
                for (int j = 0; j < exportCount; j++) {
                    writer.write(String.format("%.6f", signalData[j]));
                    if ((j + 1) % 10 == 0) {
                        writer.newLine();  // 每10个数据点换行
                    } else {
                        writer.write("\t");  // 使用制表符分隔
                    }
                }

                writer.newLine();
                writer.newLine();
            }

            System.out.println("数据已成功导出到: " + outputFilePath);
        }
    }
    // 获取信号数据
    public List<double[]> getSignalData() {
        return signalData;
    }
    // 从现有头信息创建配置
    public EDFConfig createConfigFromHeader() {
        if (header == null) {
            return null;
        }

        EDFConfig config = new EDFConfig();
        config.version = header.version;
        config.patientId = header.patientId;
        config.recordId = header.recordId;
        config.startDate = header.startDate;
        config.startTime = header.startTime;
        config.edfId = header.edfId;
        config.recordDuration = header.recordDuration;

        config.signalLabels = header.signalLabels;
        config.transducerTypes = header.transducerTypes;
        config.physicalDimensions = header.physicalDimensions;
        config.physicalMin = header.physicalMin;
        config.physicalMax = header.physicalMax;
        config.digitalMin = header.digitalMin;
        config.digitalMax = header.digitalMax;
        config.prefiltering = header.prefiltering;

        // 计算采样率
        config.samplingRates = new float[header.numberOfSignals];
        for (int i = 0; i < header.numberOfSignals; i++) {
            config.samplingRates[i] = header.samplesPerRecord[i] / header.recordDuration;
        }

        return config;
    }
    // EDF文件头信息类
    public static class EDFHeader {
        public String version;
        public String patientId;
        public String recordId;
        public String startDate;
        public String startTime;
        public int headerSize;
        public String edfId;
        public int numberOfRecords;
        public float recordDuration;
        public int numberOfSignals;

        public String[] signalLabels;
        public String[] transducerTypes;
        public String[] physicalDimensions;
        public float[] physicalMin;
        public float[] physicalMax;
        public int[] digitalMin;
        public int[] digitalMax;
        public String[] prefiltering;
        public int[] samplesPerRecord;

        @Override
        public String toString() {
            return "EDFHeader{" +
                    "version='" + version + '\'' +
                    ", patientId='" + patientId + '\'' +
                    ", startDate='" + startDate + '\'' +
                    ", startTime='" + startTime + '\'' +
                    ", numberOfSignals=" + numberOfSignals +
                    ", numberOfRecords=" + numberOfRecords +
                    ", recordDuration=" + recordDuration +
                    ", recordId=" + recordId +
                    ", headerSize=" + headerSize +
                    ", edfId=" + edfId +
                    '}';
        }
    }
    // EDF配置类，用于创建新的EDF文件
    public static class EDFConfig {
        public String version = "0";  // 标准EDF版本为0
        public String patientId = "";
        public String recordId = "";
        public String startDate = "01.01.00";  // 格式: dd.mm.yy
        public String startTime = "00.00.00";  // 格式: hh.mm.ss
        public String edfId = "EDF+C";  // 标准EDF标识

        public float recordDuration = 1;  // 每条记录持续1秒
        public String[] signalLabels;
        public String[] transducerTypes;
        public String[] physicalDimensions;
        public float[] physicalMin;
        public float[] physicalMax;
        public int[] digitalMin = new int[]{-32768};  // 默认数字最小值
        public int[] digitalMax = new int[]{32767};   // 默认数字最大值
        public String[] prefiltering;
        public float[] samplingRates;  // 采样率(Hz)
    }
    // 使用示例
    public static void main(String[] args) {
//        if (args.length == 0) {
//            System.out.println("请提供EDF文件路径");
//            return;
//        }

        try {
            EDFParser parser = new EDFParser();
//            parser.parse(new File("C:\\Users\\xinho\\Desktop\\edf文件\\S001R10.edf"));
            parser.parse(new File("C:\\Users\\xinho\\Desktop\\20250928152600.edf"));

            EDFHeader header = parser.getHeader();
            System.out.println("解析到的EDF头信息:");
            System.out.println(header);

            List<double[]> signals = parser.getSignalData();
            System.out.println("解析到 " + signals.size() + " 个信号");

            // 获取并打印所有通道名称
            List<String> channels = parser.getChannelLabels();
            System.out.println("\n通道列表:");
            for (int i = 0; i < channels.size(); i++) {
                System.out.printf("通道 %d: %s%n", i, channels.get(i));
            }

            // 打印第一个信号的前10个数据点
            if (!signals.isEmpty()) {
                String firstChannel = channels.get(0);
                double[] firstSignal = parser.getSignalByChannelName(firstChannel);
                System.out.printf("%n通道 %s 的前10个数据点:%n", firstChannel);
                for (int i = 0; i < Math.min(10, firstSignal.length); i++) {
                    System.out.printf("%.4f ", firstSignal[i]);
                }
                System.out.println();
            }
            // 导出数据到文本文件
            String outputFile = "C:\\Users\\xinho\\Desktop\\20250928152600.txt";
//             第二个参数为true时导出全部数据，false时仅导出前1000个数据点
            parser.exportToTextFile(outputFile, false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
